<?php

/**
 * Classe para manipulação de arquivos e acesso ao sistema operacional
 *
 */
class FileUtil
{
	/**
	 * Retorna true se o arquivo existir
	 *
	 * @param string $filename
	 * @return bool
	 */
	public static function Exists($filename)
	{
		return file_exists($filename);
	}
	
	/**
	 * Retorna um array com a lista de diretórios no diretório especificado
	 *
	 * @param string $folder
	 * @return array
	 */
	public static function RetrieveSubFolders($folder)
	{
		$slash = self::Slash();
		
		if ($folder{strlen($folder)-1} == $slash)
		{
			$folder = substr($folder, 0, -1);
		}
		
		if ($handle = @opendir($folder))
		{
			while ($file = @readdir($handle))
			{
				if((is_dir($folder.$slash.$file))&&(($file != "." && $file != ".." )))
				{
					$array[]=$folder.$slash.$file;
				}
			}
			@closedir($handle);
			return $array;
		}
	}

	/**
	 * Retorna um array contendo os arquivos de um diretório. Use $pattern como expressão regular para filtrar nomes de arquivos
	 * 
	 * Ex: FileUtil::RetrieveFilesFromFolder("meuDiretorio/", ".html$");
	 *
	 * @param string $folder
	 * @param string $pattern
	 * @return array
	 */
	public static function RetrieveFilesFromFolder($folder, $pattern = null)
	{
		$array = array();
		
		if ($handle = @opendir($folder))
		{
			while ($file = @readdir($handle))
			{
				if(!is_dir($folder.self::Slash().$file))
				{
					if($pattern!=null)
					{
						if (intval(preg_match("/$pattern/i", $file))>0)
						{
							$array[]=$folder.self::Slash().$file;							
						}
					}
					else
					{
						$array[]=$folder.self::Slash().$file;
					}
				}
			}
			@closedir($handle);
			return $array;
		}
		else
		{
			throw new Exception("Não foi possível abrir o diretório: $folder");
		}
	}
	

	/**
	 * Retorna o diretório de um arquivo
	 * 
	 * Ex: /dir0/dir2/arquivo.ext -> /dir0/dir2/
	 *
	 * @param string $FullFileName
	 * @return string
	 */
	public static function ExtractFilePath($file)
	{
		$path = pathinfo($file);

		return $path["dirname"] . self::Slash();
	}

	/**
	 * Retorna apenas o nome do arquivo
	 *
	 * @param string $file
	 * @return string
	 */
	public static function ExtractFileName($file)
	{
		return basename($file);
	}

	/**
	 * Ler conteúdo de um arquivo
	 *
	 * @param string $filename
	 * @return string
	 */
	public static function QuickFileRead($file)
	{
		return @file_get_contents($file);
	}
	
	/**
	 * Gravar conteúdo em um arquivo
	 * 
	 * Obs: $append especifica se o conteúdo deve ser inserido no final do arquivo
	 *
	 * @param string $filename
	 * @param string $content
	 * @param bool $append
	 */
	public static function QuickFileWrite($filename, $content, $append=null)
	{
		$mode = "w";
		if ($append != null)
		{
			$mode = "a";
		}
		
		$handle = @fopen($filename, $mode);
		@fwrite($handle, $content);
		@fclose($handle);
		@chmod($filename, 0775);
	}
	
	/**
	 * Apagar um arquivo do disco
	 *
	 * @param string $file
	 */
	public static function DeleteFileString($file)
	{
		if(file_exists($file) && !@unlink($file))
		{
			throw new Exception("Não foi possível apagar o arquivo: $file");
		}
	}
	
	/**
	 * Apagar um diretório do disco
	 *
	 * @param string $dir
	 */
	public static function DeleteDirectory($dir)
	{
		//rmdir  
		if (FileUtil::isWindowsOS())
		{
			$restul = self::Deltree($dir);
		}
		else
		{
			$restul = @exec("rm -rf $dir"); //LINUX
		}
		
		if(!$restul)
		{
			throw new Exception("Não foi possível apagar o diretório: $dir.");
		}
	}
	
	public static function Deltree($file)
	{
	    if (is_dir($file) && !is_link($file)) {
	        foreach(glob($file.'/*') as $sf) {
	            if ( !self::Deltree($sf) ) {
	                throw new Exception('Erro ao excluir: ' . $sf);
	                return false;
	            }
	        }
	        return rmdir($file);
	    } else {
	        return unlink($file);
	    }
	}	

	/**
	 * Apagar um arquivo a partir de um FilenameProcessor
	 *
	 * @param FilenameProcessor $file
	 */
	public static function DeleteFile($file)
	{
		if ($file->Extension() != '.*')
		{
			self::DeleteFileString($file->FullQualifiedNameAndPath());
		}
		else
		{
			self::DeleteFileAnyExtension($file->FullQualifiedNameAndPath());
		}
	}
	
	/**
	 * Apagar arquivo de nome especificado com qualquer extensão
	 * 
	 * Ex: arquivo.exe, arquivo.txt, arquivo.jpg
	 *
	 * @param string $filename
	 * @return bool
	 */
	public static function DeleteFileAnyExtension($filename)
	{
		$path = pathinfo($filename);
		$basefilename = basename($path['basename'], '.' . $path['extension']);
		$filenamedir = $path['dirname'];
		$arrayFiles = self::ListDirectory($path['dirname']);
		foreach ($arrayFiles as $file) {
			$filePath = pathinfo($file);
			$basename = basename($filePath['basename'], '.' . $filePath['extension']);
			if ($basefilename == $basename) {
				$filename = $filenamedir . FileUtil::Slash() . $filePath['basename'];
				self::DeleteFileString($filename);
				return true;
			}
		}
		return false;
	}
	
	/**
	 * Lista arquivos de um diretório e pode ser ordenado por ASC ou DESC
	 *
	 * @param string $dir
	 * @param string $orderby
	 * @return array
	 */
	public static function ListDirectory($dir, $orderby = 'ASC')
	{
		if ($orderby == 'ASC') {
			$orderby = 0;
		}else {
			$orderby = 1;
		}
		return scandir($dir, $orderby);
	}
	
	/**
	 * Apagar arquivos de um diretório
	 *
	 * @param FileNameProcessor $file
	 */
	public static function DeleteFilesFromPath($file)
	{
		$files = self::RetrieveFilesFromFolder($file->PathSuggested(),null);
		foreach ($files as $f)
		{
			if (strpos($f,$file->Extension())!== false)
			{
				self::DeleteFileString($f);
			}
		}
	}

	/**
	 * Retorna a "barra" de acordo com o sistema operacional
	 * 
	 * WINDOWS = \\
	 * LINUX = /
	 *
	 * @return string
	 */
	public static function Slash()
	{
		return DIRECTORY_SEPARATOR;
	}

	/**
	 * Ajusta as "barras" do caminho do aquivo de acordo com o sistema operacional
	 *
	 * @param string $path
	 * @return string
	 */
	public static function AdjustSlashes($path)
	{
		if (self::isWindowsOS())
		{
			$search = "/";
			$replace = "\\";
		}
		else
		{
			$search = "\\";
			$replace = "/";
		}
		return str_replace($search, $replace, $path);
	}

	/**
	 * Retorna o caminho absoluto do arquivo de acordo com sistema operacional
	 *
	 * @param string $absolutepath
	 * @return string
	 */
	public static function getUriFromFile($absolutepath)
	{
		if (self::isWindowsOS())
		{
			$result = "file:///".$absolutepath;

			$search = "\\";
			$replace = "/";

			$result =str_replace($search, $replace, $result);
		}
		else
		{
			$result = "file://".$absolutepath;
		}
		return $result;

	}
	
	/**
	 * Retorna true se for WINDOWS
	 *
	 * @return bool
	 */
	public static function isWindowsOS()
	{
		if (strtoupper(substr(PHP_OS, 0, 3)) === "WIN") {
			return true;
		}
		else {
			return false;
		}
	}

	/**
	 * Checa e codifica para UTF-8 a string.
	 * Retorna a string convertida para UTF-8
	 *
	 * @param string $str
	 * @return string
	 */
	public static function CheckUTF8Encode($str)
	{
		if (!self::is_utf8($str, 'UTF-8'))
		{
			$str = mb_convert_encoding($str, 'UTF-8');
		}
		else
		{
			if (ord(substr($str,0,1)) == 239)
			{
				$str = substr($str, 3);
			}
		}
		return $str;
	}

	/**
	 * Verifica se a string é UTF-8
	 *
	 * @param string $str
	 * @return bool
	 */
	public static function is_utf8($str) 
	{
		if (is_array($str))
		{
			DebugUtil::PrintValue($str . ' ' . gettype($str) , '[FileUtil] is_utf8() ' . __LINE__);
//			throw new Exception('nao é str');
		}
		return mb_check_encoding($str, 'UTF-8');
	}

	/**
	 * Cria uma estrutura de diretórios recursivamente.
	 *
	 * @author Aidan Lister <aidan@php.net> (original name mkdirr)
	 * @version 1.0.0
	 * 
	 * @param string $pathname
	 * @param int $mode
	 * @return bool
	 */
	public static function ForceDirectories($pathname, $mode = 0777)
	{
		// Crawl up the directory tree
		$next_pathname = substr($pathname,0, strrpos($pathname, self::Slash()));
		if ($next_pathname != "")
		{
			self::ForceDirectories($next_pathname, $mode);
		}
		if (!file_exists($pathname))
		{
			if(!@mkdir($pathname, $mode))
			{
				throw new Exception("Não foi possível criar o diretório $dir no modo $mode.");
			}
		}
		
	}
	
	/**
	 * Apaga um diretório e seus subdiretórios e arquivos recursivamente
	 *
	 * @author dexn (at) metazure.com (original name rmdirr)
	 * @version 1.0.0
	 * @param string $dir
	 */
	public static function ForceRemoveDirectories($dir) 
	{
	   if($objs = glob($dir."/*")){
	       foreach($objs as $obj) {
	           is_dir($obj)? self::ForceRemoveDirectories($obj) : self::DeleteFileString($obj);
	       }
	   }
	   self::DeleteDirectory($dir);
	}
	
	/**
	 * Retorna true se encontrar no diretório algum arquivo com o nome especificado
	 *
	 * @param string $dir
	 * @param string $filename
	 * @return bool
	 */
	public static function ExistsFileInDirectory($dir, $filename)
	{
		$arrayFiles = self::ListDirectory($dir, 'ASC');
		foreach ($arrayFiles as $file) {
			$filePath = pathinfo($file);
			if ($filename == basename($filePath['basename'], '.' . $filePath['extension'])) {
				return true;
			}
		}
		return false;
	}
}
?>